/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package argtrust.cmd;

import java.lang.System;
import java.util.Collection;
import java.util.List;
import java.io.File;
import java.util.ArrayList;
import static java.util.Arrays.*;

import aima.core.logic.fol.parsing.FOLParser;
import aima.core.logic.fol.parsing.ast.Sentence;
import aima.core.logic.fol.domain.FOLDomain;
import aima.core.logic.fol.Connectors;

import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionException;
import static joptsimple.util.DateConverter.*;
import joptsimple.OptionSpec;

import argtrust.logic.FOLNaturalDeduction;
import argtrust.logic.FOLKnowledgeBase;
import argtrust.logic.InferenceRule;
import argtrust.logic.InferenceNode;
import argtrust.argsys.ArgumentationSystem;
import argtrust.argsys.ArguingNode;
import argtrust.belief.BeliefBase;
import argtrust.trustnet.Agent;
import argtrust.trustnet.TrustNet;
import argtrust.trustnet.TrustNode;
import argtrust.tidal.TidalTrust;
import argtrust.tidal.TidalTrustBelief;
import argtrust.trustnet.ITrustSemantics;
import argtrust.belief.ITrustBeliefSemantics;
import argtrust.argsys.IBeliefArgumentSemantics;
import argtrust.argsys.MinBeliefArgument;
import argtrust.argsys.IArgumentationSemantics;
import argtrust.argsys.LabelGroundedSemantics;
import argtrust.argtrustgraph.IArgTrustDrawing;
import argtrust.argtrustgraph.IGraphAttributeFactory;

import argtrust.argtrustgraph.ArgTrustGraph;
import argtrust.xml.XMLTrustBeliefReader;

/**
 *
 * @author Yuqing Tang
 */
public class ArgTrust {

    //Options:
    public class OptionList {

//        File mInput = null;
        List<File> mInputFileList = null;
        File mOutput = null;
        String mAgentName = null;
        List<String> mQuestionList = null;
        String mTrustSemName = null;
        String mBeliefSemName = null;
        String mBeliefArgSemName = null;
        String mArgSemName = null;
        String mOutputType = null;
    };
    OptionList mOptionList = new OptionList();
    OptionSet mOptions;

    public void parseOptions(String args[]) throws java.lang.Exception {
        OptionParser option_parser;
        option_parser = new OptionParser();
        OptionSpec<String> question_opt;
        option_parser.accepts("i").withRequiredArg().ofType(File.class).withValuesSeparatedBy(',').describedAs("input xml").required();
        option_parser.accepts("o").withRequiredArg().ofType(File.class).describedAs("output file/folder").required();
        option_parser.accepts("a").withOptionalArg().ofType(String.class).describedAs("agent");
//                    mParser.accepts("q").withRequiredArg().ofType(String.class).describedAs("question [-q question1 -q question2 ...]");
        question_opt = option_parser.accepts("q").withOptionalArg().ofType(String.class).withValuesSeparatedBy(';').describedAs("question list: question1;question2;...");
        option_parser.acceptsAll(asList("h", "?"), "show help");

        option_parser.accepts("tr").withRequiredArg().ofType(String.class).describedAs("trust semantics name: [TidalTrust|CertPropTrust]");
        option_parser.accepts("tb").withRequiredArg().ofType(String.class).describedAs("trust-to-belief semantics name: : [TidalBelief|CertPropBelief]");
        option_parser.accepts("blarg").withRequiredArg().ofType(String.class).describedAs("belief-on-argument semantics name");
        option_parser.accepts("arg").withRequiredArg().ofType(String.class).describedAs("argumententation semantics name");
        option_parser.accepts("ot").withRequiredArg().ofType(String.class).describedAs("output type: dot|dot2tex|html");

        try {
            OptionSet mOptions = option_parser.parse(args);
            if (mOptions.has("i")) {
                mOptionList.mInputFileList = (List<File>) mOptions.valuesOf("i");
                System.out.println("i: " + mOptionList.mInputFileList.toString());
            }
            if (mOptions.has("o")) {
                mOptionList.mOutput = (File) mOptions.valueOf("o");
                System.out.println("o: " + mOptionList.mOutput.toString());
            }
            if (mOptions.has("a")) {
                mOptionList.mAgentName = (String) mOptions.valueOf("a");
                System.out.println("a: " + mOptionList.mAgentName);
            }
            if (mOptions.has("q")) {
                mOptionList.mQuestionList = (List<String>) mOptions.valuesOf(question_opt);
                System.out.println("q: " + mOptionList.mQuestionList);
            }

            if (mOptions.has("tr")) {
                mOptionList.mTrustSemName = (String) mOptions.valueOf("tr");
                System.out.println("tr: " + mOptionList.mTrustSemName);
            }
            if (mOptions.has("tb")) {
                mOptionList.mBeliefSemName = (String) mOptions.valueOf("tb");
                System.out.println("tb: " + mOptionList.mBeliefSemName);
            }
            if (mOptions.has("blarg")) {
                mOptionList.mBeliefArgSemName = (String) mOptions.valueOf("blarg");
                System.out.println("blarg: " + mOptionList.mBeliefArgSemName);
            }
            if (mOptions.has("arg")) {
                mOptionList.mArgSemName = (String) mOptions.valueOf("arg");
                System.out.println("arg: " + mOptionList.mArgSemName);
            }

            if (mOptions.has("ot")) {
                mOptionList.mOutputType = (String) mOptions.valueOf("ot");
                System.out.println("ot: " + mOptionList.mOutputType);
            }



            if (mOptions.has("?")) {
                System.out.println("Usage: "
                        + this.getClass().getName()
                        + " [options]");
                System.out.println("Example: "
                        + this.getClass().getName()
                        + " -i <input xml>"
                        + " -o <output file/folder>"
                        + " -a <agent>"
                        + " -q <question1>;<question2>;...");
                option_parser.printHelpOn(System.out);
            }
        } catch (OptionException exception) {
            System.out.println(exception.getMessage());

            System.out.println("Usage: "
                    + this.getClass().getName()
                    + " [options]");
            System.out.println("Example: "
                    + this.getClass().getName()
                    + " -i <input xml>"
                    + " -o <output file/folder>"
                    + " -a <agent>"
                    + " -q <question1>;<question2>;...");
            option_parser.printHelpOn(System.out);

            throw exception;

        }

    }
    //From inputs:
    XMLTrustBeliefReader mReader;
    TrustNet mTrustNet;
    BeliefBase mBeliefBase;
    //Internal variables:
    ArgumentationSystem mArgSys;
    ArgTrustGraph mArgTrustGraph;
    //The four semantic parameters;
    ITrustSemantics mTrustSemantics;
    ITrustBeliefSemantics mTrustBeliefSemantics;
    IBeliefArgumentSemantics mArgumentBeliefSemantics;
    IArgumentationSemantics mArgumentationSemantics;
    IArgTrustDrawing mArgTrustDrawing = null;
    IGraphAttributeFactory mGraphAttributeFactory = null;

    public void run(String[] args) {
        try {
            this.parseOptions(args);

            mReader = new XMLTrustBeliefReader();
            mReader.readFile(mOptionList.mInputFileList);
            mTrustNet = mReader.getTrustnet();

            Agent agent = parseAgent(mOptionList.mAgentName);
            if (agent == null) {
                agent = mReader.getQueryAgent();
                if (agent == null) {
                    System.out.println("No query agent specifed.");
                    return;
                }
            }
            //Argumentation system:
            mBeliefBase = mReader.getBeliefBase();
            FOLKnowledgeBase kb = new FOLKnowledgeBase();
            kb.acceptKnowledgeBase(mBeliefBase.getFactSet(), mBeliefBase.getRuleSet());
            mArgSys = new ArgumentationSystem(kb);
            mArgSys.acceptDefeatRules(mReader.getDefeatRuleList());
            List<ArguingNode> arg_node_list =
                    this.parseQuestionList();
//            arg_node_list = null;
            if (arg_node_list == null) {
                System.out.println("No arguments can be produced for the given query");
//                return;
            }

            mArgTrustGraph = new ArgTrustGraph();
            parseGraphDrawing();
            System.out.println(mArgTrustGraph.getAttributesFactory().getName() + " is used.");
            mArgTrustGraph.setArgSys(mArgSys);
            mArgTrustGraph.setBeliefBase(mReader.getBeliefBase());
            mArgTrustGraph.setTrustNet(mTrustNet);
            mTrustSemantics =
                    parseTrustSemantics();
            mArgTrustGraph.setTrustSemantics(mTrustSemantics);
            mTrustBeliefSemantics =
                    parseTrustBeliefSemantics();
            mArgTrustGraph.setTrustBeliefSemantics(mTrustBeliefSemantics);
            mArgumentBeliefSemantics =
                    parseArgumentBeliefSemantics();
            mArgTrustGraph.setArgumentBeliefSemantics(mArgumentBeliefSemantics);
            mArgumentationSemantics =
                    parseArgumentationSemantics();
            mArgTrustGraph.setArgumentationSemantics(mArgumentationSemantics);
            mArgTrustGraph.draw(arg_node_list,
                    mTrustNet.getTrustNode(agent));
            mArgTrustGraph.close();
        } catch (OptionException e) {
            /* Argument parsing errors are already handled.*/
        } catch (java.lang.Exception e) {
            e.printStackTrace(System.out);
        }
    }

    Agent parseAgent(String agent_name) {
        Agent agent;
        if (agent_name == null) {
            agent = mReader.getQueryAgent();
        } else {
            if (!mReader.getTrustnet().hasAgent(agent_name)) {
                System.out.println("Query agent \"" + agent_name + "\" is not in the trustnet.");
                return null;
            }
            agent = mReader.getTrustnet().getAgent(agent_name);
        }
        return agent;
    }

    List<ArguingNode> parseQuestionList() {
        List<ArguingNode> arg_node_list = null;
        if (mOptionList.mQuestionList == null) {
            arg_node_list =
                    mArgSys.getArguingNodeList(mReader.getQuestionLst());
        } else {
            List<Sentence> sentence_list = new ArrayList();
            System.out.println("Query List is: " + mOptionList.mQuestionList);
            for (String question : mOptionList.mQuestionList) {
//                System.out.println("Adding query to list :" + question);
                sentence_list.add(mReader.getFolParser().parse(question));
            }
            arg_node_list = mArgSys.getArguingNodeList(sentence_list);

        }
        return arg_node_list;
    }

    void parseGraphDrawing() {
        if (mOptionList.mOutputType == null) {
            mGraphAttributeFactory =
                    new argtrust.out.graphviz.GVZDot2TexAttributeFactory(mArgTrustGraph);
            mArgTrustDrawing =
                    new argtrust.out.graphviz.GVZArgTrustDrawing(mArgTrustGraph);
            mArgTrustGraph.setDrawingOutput(
                    mArgTrustDrawing,
                    mGraphAttributeFactory);
            mArgTrustGraph.openFile(mOptionList.mOutput);

        } else if (mOptionList.mOutputType.equals("html")) {
            mArgTrustDrawing =
                    new argtrust.out.html.core.HtmlArgTrustDrawing(mArgTrustGraph);
            mGraphAttributeFactory =
                    new argtrust.out.html.core.HtmlAttributeFactory(mArgTrustGraph);
            ((argtrust.out.html.core.HtmlArgTrustDrawing) mArgTrustDrawing).getHtmlAdaptor().setOutputPath(
                    mOptionList.mOutput);

            mArgTrustGraph.setDrawingOutput(
                    mArgTrustDrawing,
                    mGraphAttributeFactory);
        } else if (mOptionList.mOutputType.equals("dot")) {
            mGraphAttributeFactory =
                    new argtrust.out.graphviz.GVZAttributeFactory(mArgTrustGraph);
            mArgTrustDrawing =
                    new argtrust.out.graphviz.GVZArgTrustDrawing(mArgTrustGraph);
            mArgTrustGraph.setDrawingOutput(
                    mArgTrustDrawing,
                    mGraphAttributeFactory);
            mArgTrustGraph.openFile(mOptionList.mOutput);

        } else if (mOptionList.mOutputType.equals("dot2tex")) {
            mGraphAttributeFactory =
                    new argtrust.out.graphviz.GVZDot2TexAttributeFactory(mArgTrustGraph);
            mArgTrustDrawing =
                    new argtrust.out.graphviz.GVZArgTrustDrawing(mArgTrustGraph);
            mArgTrustGraph.setDrawingOutput(
                    mArgTrustDrawing,
                    mGraphAttributeFactory);
            mArgTrustGraph.openFile(mOptionList.mOutput);

        }
    }

    ITrustSemantics parseTrustSemantics() {
        ITrustSemantics res = null;
        if (mOptionList.mTrustSemName == null) {
            res = new TidalTrust(mReader.getTrustnet(), 0);

        } else if (mOptionList.mTrustSemName.equals("TidalTrust")) {
            res = new TidalTrust(mReader.getTrustnet(), 0);
        } else if (mOptionList.mTrustSemName.equals("CertPropTrust")) {
            res = new argtrust.certprop.CertPropTrust(mTrustNet);
        } else {
            res = new TidalTrust(mReader.getTrustnet(), 0);

        }

        return res;
    }

    ITrustBeliefSemantics parseTrustBeliefSemantics() {
        ITrustBeliefSemantics res = null;
        if (mOptionList.mBeliefSemName == null) {
            res = new TidalTrustBelief(mBeliefBase, mTrustSemantics);

        } else if (mOptionList.mBeliefSemName.equals("TidalBelief")) {
            res = new TidalTrustBelief(mBeliefBase, mTrustSemantics);
        } else if (mOptionList.mBeliefSemName.equals("CertPropBelief")) {
            res = new argtrust.certprop.CertPropBelief(mBeliefBase, mTrustSemantics);
        } else {
            res = new TidalTrustBelief(mBeliefBase, mTrustSemantics);
        }
        return res;
    }

    IBeliefArgumentSemantics parseArgumentBeliefSemantics() {
        IBeliefArgumentSemantics res = null;
        if (mOptionList.mBeliefArgSemName == null) {
            res = new MinBeliefArgument(mTrustBeliefSemantics);

        } else if (mOptionList.mBeliefArgSemName.equals("MinBeliefArg")) {
            res = new MinBeliefArgument(mTrustBeliefSemantics);
        } else {
            res = new MinBeliefArgument(mTrustBeliefSemantics);
        }
        return res;
    }

    IArgumentationSemantics parseArgumentationSemantics() {
        IArgumentationSemantics res = null;
        if (mOptionList.mArgSemName == null) {
            res = new LabelGroundedSemantics(mArgSys, mArgumentBeliefSemantics);

        } else if (mOptionList.mArgSemName.equals("MinBeliefArg")) {
            res = new LabelGroundedSemantics(mArgSys, mArgumentBeliefSemantics);
        } else {
            //TODO: error message.
            res = new LabelGroundedSemantics(mArgSys, mArgumentBeliefSemantics);
        }
        return res;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        ArgTrust arg_trust = new ArgTrust();
        arg_trust.run(args);
    }
}
